package per.hnvcam.searchext.controller.administration;

import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import per.hnvcam.common.OrderedSet;
import per.hnvcam.common.impl.OrderedSetImpl;
import per.hnvcam.hedge.algebra.Hedge2AlgebraDefinition;
import per.hnvcam.hedge.algebra.Hedge2Quantifier;
import per.hnvcam.searchext.services.TrainingService;
import per.hnvcam.searchext.services.ForecastService;
import per.hnvcam.searchext.services.RuleService;
import per.hnvcam.searchext.services.SpecialQuery;
import per.hnvcam.searchext.data.dao.WebReferenceDAO;
import per.hnvcam.searchext.data.dao.WordCountDAO;
import per.hnvcam.searchext.data.dao.WordDAO;
import per.hnvcam.searchext.data.model.SystemConfiguration;
import per.hnvcam.searchext.data.model.WebReference;
import per.hnvcam.searchext.data.model.Word;
import per.hnvcam.searchext.data.model.WordCount;

@Controller("GeneralController")
public class GeneralController {

   private static final String ADMIN_HOME_PAGE = "administration/home";
   private static final String ADMIN_SYSTEM_PAGE = "administration/system";
   private static final String PAGE_DETAILS_PAGE = "administration/page";
   private static final String ADMIN_WORDS_PAGE = "administration/words";

   @Autowired
   @Qualifier("WebReferenceDAO")
   private WebReferenceDAO webReferenceDAO;

   @Autowired
   @Qualifier("WordCountDAO")
   private WordCountDAO wordCountDAO;

   @Autowired
   @Qualifier("WordDAO")
   private WordDAO wordDAO;

   @Autowired
   @Qualifier("SpecialQuery")
   private SpecialQuery specialQuery;

   @Autowired
   @Qualifier("ForecastService")
   private ForecastService forecastService;

   @Autowired
   @Qualifier("RuleService")
   private RuleService ruleService;

   @Autowired
   @Qualifier("TrainingService")
   private TrainingService trainingService;

   @Autowired
   @Qualifier("Hedge2AlgebraDefinition")
   private Hedge2AlgebraDefinition hedgeAlgebraDefinition;

   @Autowired
   @Qualifier("Hedge2Quantifier")
   private Hedge2Quantifier fuzzyQuantifier;

   @RequestMapping(value = "/administration/home.jhtml", method = RequestMethod.GET)
   public String showAdminHome(HttpServletRequest request, Model model) {
      SystemConfiguration systemConfiguration = specialQuery.getSystemConfiguration();
      model.addAttribute("classifiedClasses", systemConfiguration.getClasses());
      model.addAttribute("pageList", webReferenceDAO.listPages());
      model.addAttribute("newPage", new WebReference());
      return ADMIN_HOME_PAGE;
   }

   @RequestMapping(value = "/administration/home.jhtml", method = RequestMethod.POST)
   public String addNewPage(HttpServletRequest request, @ModelAttribute("newPage") WebReference webReference, Model model) {
      String status;
      try {
         webReferenceDAO.savePage(webReference);
         status = "Page was added successfully.";
      }
      catch (Exception e) {
         e.printStackTrace();
         status = "Could not add new page: " + e.getMessage();
      }

      try {
         trainingService.trainFromWebReference(webReference);
      }
      catch (Exception e) {
         e.printStackTrace();
         status = "Could not train from page";
      }

      SystemConfiguration systemConfiguration = specialQuery.getSystemConfiguration();
      model.addAttribute("classifiedClasses", systemConfiguration.getClasses());
      model.addAttribute("pageList", webReferenceDAO.listPages());
      model.addAttribute("status", status);
      return ADMIN_HOME_PAGE;
   }

   @RequestMapping(value = "/administration/system.jhtml", method = RequestMethod.GET)
   public String showSystemConfiguration(HttpServletRequest request, Model model) {
      SystemConfiguration systemConfiguration = specialQuery.getSystemConfiguration();
      model.addAttribute("initialRuleSetSize",
            forecastService.determineInitialRulesSetSize(systemConfiguration.getRuleLengthMinimum(),
                  systemConfiguration.getRuleLengthMaximum(), ruleService.getAllBaseRulesData()));
      model.addAttribute("systemConfiguration", systemConfiguration);
      return ADMIN_SYSTEM_PAGE;
   }

   @RequestMapping(value = "/administration/system.jhtml", method = RequestMethod.POST)
   public String saveSystemConfiguration(HttpServletRequest request, @ModelAttribute("systemConfiguration") SystemConfiguration systemConfiguration,
                                Model model) {
      model.addAttribute("status", specialQuery.saveSystemConfiguration(systemConfiguration));
      model.addAttribute("initialRuleSetSize",
            forecastService.determineInitialRulesSetSize(systemConfiguration.getRuleLengthMinimum(),
                  systemConfiguration.getRuleLengthMaximum(), ruleService.getAllBaseRulesData()));
      return ADMIN_SYSTEM_PAGE;
   }



   @RequestMapping(value = "/administration/page.jhtml", method = RequestMethod.GET)
   public String showPageDetails(HttpServletRequest request, @RequestParam("pageId") long pageId, Model model) {
      WebReference pageDetails = webReferenceDAO.findById(pageId);
      List<WordCount> wordCounts = wordCountDAO.findByWebReferenceId(pageId);
      model.addAttribute("pageDetails", pageDetails);
      model.addAttribute("wordCounts", wordCounts);
      return PAGE_DETAILS_PAGE;
   }

   @RequestMapping(value = "/administration/wordsSummary.jhtml", method = RequestMethod.GET)
   public String showWordsInformation(@RequestParam(value = "operation", required = false) String operation, Model model) {
      if (operation != null && operation.equals("fuzzy")) {
         determineWordAmount();
      }



      Map<Long, Map<Long, WordCount>> wordMap = specialQuery.getWordSummary();
      List<Word> wordList = wordDAO.listWords();
      List<WebReference> webReferenceList = webReferenceDAO.listPages();

      model.addAttribute("wordList", wordList);
      model.addAttribute("wordMap", wordMap);
      model.addAttribute("pages", webReferenceList);
      return ADMIN_WORDS_PAGE;
   }

   private void determineWordAmount() {
      List<Word> wordList = wordDAO.listWords();
      OrderedSet<String> domain = hedgeAlgebraDefinition.getDomainOfLength(2);
      OrderedSet<Double> ranges = fuzzyQuantifier.getFuzzinessInterval(2);
      for (Word word : wordList) {
         if (word.getMaxCount() < domain.size()) continue;
         OrderedSet<Double> fuzzinessIntervals = multiply(ranges, word.getMaxCount());
         List<WordCount> wordCounts = wordCountDAO.findByWord(word);
         for (WordCount wc : wordCounts) {
            for (int i = 0; i < domain.size(); i++) {
               if (wc.getCount() > fuzzinessIntervals.getAt(i) && ( wc.getCount() <= fuzzinessIntervals.getAt(i+1) ||
                  i == (domain.size() - 1) ) ) {
                  wc.setFuzzyAmount(domain.getAt(i));
                  wordCountDAO.saveOrUpdate(wc);
               }
            }
         }
      }
   }

   private OrderedSet<Double> multiply(OrderedSet<Double> item, double by) {
      OrderedSet<Double> result = new OrderedSetImpl<Double>();
      for (Double d : item) {
         result.add(d * by);
      }
      return result;
   }
}
